package net.melon.sysres.inst;

import java.io.Serializable;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.inject.Named;
import javax.inject.Singleton;

import net.esj.basic.core.engine.util.enumeration.EnumProvider;
import net.esj.basic.core.engine.util.enumeration.EnumProvidersFactory;
import net.esj.basic.core.engine.util.enumeration.EnumVo;
import net.esj.basic.core.engine.util.tree.TreeProvider;
import net.esj.basic.dao.hibernate.HibernateQueryBuilder;
import net.esj.basic.dao.querybuilder.QueryBuilder;
import net.esj.basic.dao.querybuilder.QueryBuilderFactory;
import net.esj.basic.pojo.EnumStructure;
import net.esj.basic.pojo.TreeStructure;
import net.esj.basic.pojo.op.Operator;
import net.esj.basic.service.impl.DefaultServiceImpl;
import net.esj.basic.utils.DateUtils;
import net.esj.basic.utils.Pagination;
import net.esj.basic.utils.Validators;
import net.melon.sysres.manager.ResourceManager;
import net.melon.sysres.pojo.Resource;

import org.apache.commons.lang.StringUtils;


@Singleton
@Named("resourceManager")
public class ResourceManagerImpl extends DefaultServiceImpl implements
		ResourceManager{

	@Override
	public List<Resource> loadAllResources() {
		List<Resource> root = loadResources(null);
		for(Resource res : root){
			loadChild(res);
		}
		return root;
	}

	private void loadChild(Resource res){
		if(!res.getChildren().isEmpty()){
			for(Resource child : res.getChildren()){
				loadChild(child);
			}
		}
	}
	
	@Override
	public List<Resource> loadResources(Resource parent) {
		QueryBuilder<Resource> qb =  QueryBuilderFactory.create(HibernateQueryBuilder.class,Resource.class);
		if(parent==null || Validators.isEmpty(parent.getId())){
			qb.isNull("parent");
		}else{
			qb.eq("parent", parent);
		}
		qb.OrderByAsc("ordinal").OrderByAsc("keyCode").OrderByDesc("gmtCreate");
		List<Resource> list =  queryListByQueryBuilder(qb);
		return list;
	}
	
	@Override
	public List<Resource> loadResourcesByType(Resource parent, String type) {
		QueryBuilder<Resource> qb =  QueryBuilderFactory.create(HibernateQueryBuilder.class,Resource.class);
		if(parent==null || Validators.isEmpty(parent.getId())){
			qb.isNull("parent");
		}else{
			qb.eq("parent", parent);
		}
		qb.eq("keyType", type);
		return null;
	}
	
	@Override
	public Resource saveResource(Resource resource,boolean codeGenerate,Operator operator) {
		if(resource.getParent()!=null && Validators.isEmpty(resource.getParent().getId())){
			resource.setParent(null);
		}
		if(codeGenerate){
			generateResourceCode(resource);
		}else{
			resource.setKeyCode(0);
		}
		generateResourceOrdinal(resource);
		Date now = DateUtils.now();
		resource.setGmtCreate(now);
		resource.setGmtModify(now);
		resource.setCreater(operator.getId().toString());
		save(resource);
		return resource;
	}
	
	@Override
	public Resource updateResource(Resource resource,Operator operator) {
		Resource old = get(resource.getId(), Resource.class);
		old.setCascading(resource.isCascading());
		old.setName(resource.getName());
		old.setComments(resource.getComments());
		old.setKeyType(resource.getKeyType());
		old.setKeyValue(resource.getKeyValue());
		old.setGmtModify(new Date());
		old.setOrdinal(resource.getOrdinal());
		old.setParentCode(resource.getParentCode());
		old.setParent(resource.getParent());
		old.setModifier(operator.getId().toString());
		old.setPriority(resource.getPriority());
		old.setHasLeaf(resource.isHasLeaf());
		if(Validators.isEmpty(old.getParent().getId())){
			old.setParent(null);
		}
		update(old);
		return resource;
	}

	@Override
	public List<Resource> loadFirstNodeResourcesByType(String type) {
		return loadResourcesByType(type,0,true);
	}

	@Override
	public List<Resource> loadResourcesByType(String type, int parentCode,boolean fetchParent) {
		QueryBuilder<Resource> qb =  QueryBuilderFactory.create(HibernateQueryBuilder.class,Resource.class);
		qb.eq("keyType", type);
//		if(parentCode > 0){
//			qb.eq("parentCode", parentCode);
//		}
		if(fetchParent){
			qb.fetch("parent");
		}
		qb.OrderByAsc("ordinal").OrderByDesc("gmtCreate");
		List<Resource> list= queryListByQueryBuilder(qb);
		return list;
	}
	
	@Override
	public Resource findFirstResourceByType(String type,int code) {
		QueryBuilder<Resource> qb =  QueryBuilderFactory.create(HibernateQueryBuilder.class,Resource.class);
		qb.eq("keyType", type).eq("keyCode", code);
		qb.OrderByAsc("ordinal").OrderByDesc("gmtCreate");
		return (Resource) queryFirst(qb);
	}
	
	
	/**
	 * 第一层255个对象 以下每层256个对象
	 * 根节点code为0
	 * 第一层1~255  节点n的下一层 n<<8~(n+1)<<8-1 以此类推 
	 * @param res
	 */
	private void generateResourceCode(Resource res){
		QueryBuilder<Resource> qb = QueryBuilderFactory.create(HibernateQueryBuilder.class,Resource.class);
		if(res.getParent()==null){//根节点默认code永远为0
			qb.isNull("parent");
			res.setKeyCode(0);
			return;
		}else{
			qb.eq("parent", res.getParent());
		}
		qb.OrderByAsc("keyCode");
		List<Resource> list = queryListByQueryBuilder(qb);//获得该父节点下子节点(兄弟节点);
		
		int min =Math.max((res.getParentCode()<<8),1);
		int max =  ((res.getParentCode()+1)<<8)-1;
		int now = min;
		while(now <= max){
			boolean exists = false;
			for(Resource tmp : list){
				if(now == tmp.getKeyCode()){
					now ++;
					exists = true;
					break;
				}
			}
			if(!exists){
				res.setKeyCode(now);
				return ;
			}else{
				exists = false;
			}
		}
		
		throw new ArrayIndexOutOfBoundsException("over.max.tree.count");
	}

	@Override
	public Resource getResource(String id) {
		return get(id, Resource.class);
	}
	
	@Override
	public Pagination<Resource> pageResources(
			Pagination<Resource> pagination) {
		return queryPageByQueryBuilder(pagination);
	}

	@Override
	public Resource findResourceByTypeAndValue(String type, String value) {
		QueryBuilder<Resource> qb = QueryBuilderFactory.create(Resource.class);
		qb.eq("keyType", type).eq("keyValue", value);
		Resource resource = (Resource) queryFirst(qb);
		return resource;
	}
	
	@Override
	public Resource findResourceByTypeAndName(String type, String name) {
		QueryBuilder<Resource> qb = QueryBuilderFactory.create(Resource.class);
		qb.eq("keyType", type).eq("name", name);
		Resource resource = (Resource) queryFirst(qb);
		return resource;
	}
	
	/**
	 * 自动生成排序号
	 * @param res
	 */
	private void generateResourceOrdinal(Resource res){
		QueryBuilder<Resource> qb = createQueryBuilder(Resource.class);
		if(res.getParent()==null){//根节点默认code永远为0
			qb.isNull("parent");
			return;
		}else{
			qb.eq("parent", res.getParent());
		}
		Object o = queryMaxByQueryBuilder(qb, "ordinal");
		if(o==null){
			res.setOrdinal(0);
		}else{
			long c = 0;
			if(o instanceof Number){
				c = ((Number)o).longValue();
			}
			res.setOrdinal((int) (c+1));
		}
	}
}
